/**
 * Uniapp HTTP请求封装
 * 支持请求/响应拦截、超时处理、文件上传下载、请求重试和取消
 * 零配置，直接引入使用
 */
import {
	useUserStore
} from "../stores/user";

class Http {
	constructor() {
		// 默认配置
		this.config = {
			baseURL: 'http://47.94.6.186:3001/api', // 基础URL
			timeout: 60000, // 默认超时时间(ms)
			header: { // 默认请求头
				'Content-Type': 'application/json'
			},
			retry: {
				count: 0, // 默认不重试
				delay: 1000, // 重试延迟时间(ms)
				// 需要重试的状态码
				statusCodes: [408, 500, 502, 503, 504]
			}
		};

		// 拦截器
		this._requestInterceptor = null;
		this._responseInterceptor = null;
		this._errorInterceptor = null;

		// 用于取消请求的令牌映射
		this.cancelTokens = new Map();

		// 默认拦截器实现
		this.initDefaultInterceptors();
	}

	/**
	 * 初始化默认拦截器
	 */
	initDefaultInterceptors() {
		// 默认请求拦截器：添加token
		this.interceptors.request.use((config) => {
			const userStore = useUserStore()
			const token = userStore.token;
			if (token) {
				// config.header.Authorization = `Bearer ${token}`;
				config.header.token = userStore.token
			}
			return config;
		});

		// 默认响应拦截器
		this.interceptors.response.use(
			(response) => {
				// 处理JSON响应
				if (typeof response.data === 'string') {
					try {
						response.data = JSON.parse(response.data);
					} catch (e) {
						// 非JSON数据不处理
					}
				}

				// 基础错误处理
				if (response.statusCode && response.statusCode >= 400) {
					const errorMsg = response.data?.message || `请求错误: ${response.statusCode}`;
					uni.showToast({
						title: errorMsg,
						icon: 'none'
					});
					throw new Error(errorMsg);
				}

				return response.data;
			},
			(error) => {
				// 默认错误提示
				let errorMsg = '网络异常，请稍后重试';
				if (error.code === 'TIMEOUT') {
					errorMsg = '请求超时，请稍后重试';
				} else if (error.message) {
					errorMsg = error.message;
				}

				uni.showToast({
					title: errorMsg,
					icon: 'none'
				});
				throw error;
			}
		);
	}

	/**
	 * 生成取消令牌
	 * @returns {String} 令牌ID
	 */
	generateCancelToken() {
		const token = Date.now() + '_' + Math.random().toString(36).substr(2, 9);
		this.cancelTokens.set(token, null);
		return token;
	}

	/**
	 * 取消请求
	 * @param {String} token 取消令牌
	 * @param {String} reason 取消原因
	 */
	cancelRequest(token, reason = '请求已取消') {
		if (this.cancelTokens.has(token)) {
			const abort = this.cancelTokens.get(token);
			if (typeof abort === 'function') {
				abort(reason);
			}
			this.cancelTokens.delete(token);
		}
	}

	/**
	 * 拦截器定义
	 */
	interceptors = {
		request: {
			use: (callback) => {
				if (typeof callback === 'function') {
					this._requestInterceptor = callback;
				} else {
					console.error('请求拦截器必须是一个函数');
				}
			}
		},
		response: {
			use: (successCallback, errorCallback) => {
				if (typeof successCallback === 'function') {
					this._responseInterceptor = successCallback;
				} else {
					console.error('响应拦截器成功回调必须是一个函数');
				}

				if (typeof errorCallback === 'function') {
					this._errorInterceptor = errorCallback;
				} else {
					console.error('响应拦截器错误回调必须是一个函数');
				}
			}
		}
	};

	/**
	 * 设置配置项
	 * @param {Object} config 配置对象
	 */
	setConfig(config) {
		if (typeof config === 'object') {
			this.config = {
				...this.config,
				...config
			};
			// 处理重试配置的合并
			if (config.retry) {
				this.config.retry = {
					...this.config.retry,
					...config.retry
				};
			}
		} else {
			console.error('配置必须是一个对象');
		}
	}

	/**
	 * 核心请求方法（带重试功能）
	 * @param {Object} options 请求选项
	 * @param {Number} retryCount 当前重试次数
	 * @returns {Promise}
	 */
	request(options = {}, retryCount = 0) {
		// 合并配置
		const {
			url,
			method = 'GET',
			data = {},
			header = {},
			timeout = this.config.timeout,
			retry = {},
			cancelToken // 取消令牌
		} = options;

		// 合并重试配置
		const retryConfig = {
			...this.config.retry,
			...retry
		};

		// 验证URL
		if (!url) {
			return Promise.reject(new Error('请求URL不能为空'));
		}

		// 处理URL
		let requestUrl = url;
		if (this.config.baseURL && !url.startsWith('http')) {
			// 处理baseURL结尾和url开头的斜杠问题
			const baseEndsWithSlash = this.config.baseURL.endsWith('/');
			const urlStartsWithSlash = url.startsWith('/');

			if (baseEndsWithSlash && urlStartsWithSlash) {
				requestUrl = this.config.baseURL + url.substring(1);
			} else if (!baseEndsWithSlash && !urlStartsWithSlash) {
				requestUrl = this.config.baseURL + '/' + url;
			} else {
				requestUrl = this.config.baseURL + url;
			}
		}

		// 合并请求头
		const requestHeader = {
			...this.config.header,
			...header
		};

		// 构建请求参数
		let requestOptions = {
			url: requestUrl,
			method: method.toUpperCase(),
			data,
			header: requestHeader,
			timeout
		};

		// 执行请求拦截器
		if (this._requestInterceptor) {
			try {
				const modifiedOptions = this._requestInterceptor(requestOptions);
				if (modifiedOptions) {
					requestOptions = modifiedOptions;
				}
			} catch (error) {
				return Promise.reject(error);
			}
		}

		// 返回Promise
		return new Promise((resolve, reject) => {
			// 处理取消请求
			if (cancelToken && this.cancelTokens.has(cancelToken)) {
				this.cancelTokens.set(cancelToken, (reason) => {
					const error = new Error(reason);
					error.code = 'CANCEL';
					reject(error);
				});
			}

			// 超时处理定时器
			const timeoutTimer = setTimeout(() => {
				task.abort();
				const timeoutError = new Error('请求超时');
				timeoutError.code = 'TIMEOUT';
				timeoutError.statusCode = 408;

				// 请求完成，移除取消令牌
				if (cancelToken) {
					this.cancelTokens.delete(cancelToken);
				}

				// 检查是否需要重试
				if (retryConfig.count > retryCount &&
					retryConfig.statusCodes.includes(408)) {
					// 延迟重试
					setTimeout(() => {
						this.request(options, retryCount + 1)
							.then(resolve)
							.catch(reject);
					}, retryConfig.delay);
				} else {
					if (this._errorInterceptor) {
						try {
							this._errorInterceptor(timeoutError);
						} catch (interceptorError) {
							return reject(interceptorError);
						}
					}
					reject(timeoutError);
				}
			}, timeout);

			// 发起请求
			const task = uni.request({
				...requestOptions,
				success: (response) => {
					// 优先清除超时定时器（关键修复）
					clearTimeout(timeoutTimer);

					// 请求完成，移除取消令牌
					if (cancelToken) {
						this.cancelTokens.delete(cancelToken);
					}

					// 执行响应拦截器
					if (this._responseInterceptor) {
						try {
							const processedResponse = this._responseInterceptor(response);
							resolve(processedResponse);
						} catch (error) {
							// 检查是否需要重试
							if (retryConfig.count > retryCount &&
								retryConfig.statusCodes.includes(response.statusCode)) {
								// 延迟重试
								setTimeout(() => {
									this.request(options, retryCount + 1)
										.then(resolve)
										.catch(reject);
								}, retryConfig.delay);
							} else {
								if (this._errorInterceptor) {
									this._errorInterceptor(error);
								}
								reject(error);
							}
						}
					} else {
						resolve(response);
					}
				},
				fail: (error) => {
					// 优先清除超时定时器（关键修复）
					clearTimeout(timeoutTimer);

					// 请求完成，移除取消令牌
					if (cancelToken) {
						this.cancelTokens.delete(cancelToken);
					}

					// 检查是否需要重试（不是取消错误且还有重试次数）
					if (error.code !== 'CANCEL' && retryConfig.count > retryCount) {
						// 延迟重试
						setTimeout(() => {
							this.request(options, retryCount + 1)
								.then(resolve)
								.catch(reject);
						}, retryConfig.delay);
					} else {
						// 执行错误拦截器
						if (this._errorInterceptor) {
							try {
								this._errorInterceptor(error);
							} catch (interceptorError) {
								return reject(interceptorError);
							}
						}
						reject(error);
					}
				}
			});

			// 请求完成后清除超时定时器（双重保障）
			const originalFinally = task.finally;
			task.finally = function(callback) {
				clearTimeout(timeoutTimer);
				return originalFinally.call(this, callback);
			};
		});
	}

	/**
	 * GET请求
	 * @param {String} url 请求URL
	 * @param {Object} data 请求参数
	 * @param {Object} options 额外选项
	 * @returns {Promise}
	 */
	get(url, data = {}, options = {}) {
		return this.request({
			...options,
			url,
			method: 'GET',
			data
		});
	}

	/**
	 * POST请求
	 * @param {String} url 请求URL
	 * @param {Object} data 请求参数
	 * @param {Object} options 额外选项
	 * @returns {Promise}
	 */
	post(url, data = {}, options = {}) {
		return this.request({
			...options,
			url,
			method: 'POST',
			data
		});
	}

	/**
	 * PUT请求
	 * @param {String} url 请求URL
	 * @param {Object} data 请求参数
	 * @param {Object} options 额外选项
	 * @returns {Promise}
	 */
	put(url, data = {}, options = {}) {
		return this.request({
			...options,
			url,
			method: 'PUT',
			data
		});
	}

	/**
	 * PATCH请求
	 * @param {String} url 请求URL
	 * @param {Object} data 请求参数
	 * @param {Object} options 额外选项
	 * @returns {Promise}
	 */
	patch(url, data = {}, options = {}) {
		return this.request({
			...options,
			url,
			method: 'PATCH',
			data
		});
	}

	/**
	 * DELETE请求
	 * @param {String} url 请求URL
	 * @param {Object} data 请求参数
	 * @param {Object} options 额外选项
	 * @returns {Promise}
	 */
	delete(url, data = {}, options = {}) {
		return this.request({
			...options,
			url,
			method: 'DELETE',
			data
		});
	}

	/**
	 * 上传文件（带重试功能）
	 * @param {String} url 上传URL
	 * @param {Object} options 上传选项
	 * @param {Number} retryCount 当前重试次数
	 * @returns {Promise}
	 */
	upload(url, options = {}, retryCount = 0) {
		const {
			filePath,
			name = 'file',
			formData = {},
			header = {},
			timeout = this.config.timeout,
			retry = {},
			cancelToken // 取消令牌
		} = options;

		// 合并重试配置
		const retryConfig = {
			...this.config.retry,
			...retry
		};

		// 验证参数
		if (!url) {
			return Promise.reject(new Error('上传URL不能为空'));
		}
		if (!filePath) {
			return Promise.reject(new Error('文件路径不能为空'));
		}

		// 处理URL
		let requestUrl = url;
		if (this.config.baseURL && !url.startsWith('http')) {
			requestUrl = this.config.baseURL + url;
		}

		// 合并请求头
		const requestHeader = {
			...this.config.header,
			...header
		};
		// 移除Content-Type，避免与上传冲突
		delete requestHeader['Content-Type'];

		// 构建上传参数
		let uploadOptions = {
			url: requestUrl,
			filePath,
			name,
			formData,
			header: requestHeader,
			timeout
		};

		// 执行请求拦截器
		if (this._requestInterceptor) {
			try {
				const modifiedOptions = this._requestInterceptor(uploadOptions);
				if (modifiedOptions) {
					uploadOptions = modifiedOptions;
				}
			} catch (error) {
				return Promise.reject(error);
			}
		}

		return new Promise((resolve, reject) => {
			// 处理取消请求
			if (cancelToken && this.cancelTokens.has(cancelToken)) {
				this.cancelTokens.set(cancelToken, (reason) => {
					const error = new Error(reason);
					error.code = 'CANCEL';
					reject(error);
				});
			}

			// 超时处理定时器
			const timeoutTimer = setTimeout(() => {
				task.abort();
				const timeoutError = new Error('上传超时');
				timeoutError.code = 'UPLOAD_TIMEOUT';

				// 请求完成，移除取消令牌
				if (cancelToken) {
					this.cancelTokens.delete(cancelToken);
				}

				// 检查是否需要重试
				if (retryConfig.count > retryCount &&
					retryConfig.statusCodes.includes(408)) {
					// 延迟重试
					setTimeout(() => {
						this.upload(url, options, retryCount + 1)
							.then(resolve)
							.catch(reject);
					}, retryConfig.delay);
				} else {
					if (this._errorInterceptor) {
						try {
							this._errorInterceptor(timeoutError);
						} catch (interceptorError) {
							return reject(interceptorError);
						}
					}
					reject(timeoutError);
				}
			}, timeout);

			const task = uni.uploadFile({
				...uploadOptions,
				success: (response) => {
					// 优先清除超时定时器（关键修复）
					clearTimeout(timeoutTimer);

					// 请求完成，移除取消令牌
					if (cancelToken) {
						this.cancelTokens.delete(cancelToken);
					}

					// 尝试解析JSON
					try {
						response.data = JSON.parse(response.data);
					} catch (e) {
						// 非JSON数据不处理
					}

					// 执行响应拦截器
					if (this._responseInterceptor) {
						try {
							const processedResponse = this._responseInterceptor(response);
							resolve(processedResponse);
						} catch (error) {
							// 检查是否需要重试
							if (retryConfig.count > retryCount &&
								retryConfig.statusCodes.includes(response.statusCode)) {
								// 延迟重试
								setTimeout(() => {
									this.upload(url, options, retryCount + 1)
										.then(resolve)
										.catch(reject);
								}, retryConfig.delay);
							} else {
								if (this._errorInterceptor) {
									this._errorInterceptor(error);
								}
								reject(error);
							}
						}
					} else {
						resolve(response);
					}
				},
				fail: (error) => {
					// 优先清除超时定时器（关键修复）
					clearTimeout(timeoutTimer);

					// 请求完成，移除取消令牌
					if (cancelToken) {
						this.cancelTokens.delete(cancelToken);
					}

					// 检查是否需要重试（不是取消错误且还有重试次数）
					if (error.code !== 'CANCEL' && retryConfig.count > retryCount) {
						// 延迟重试
						setTimeout(() => {
							this.upload(url, options, retryCount + 1)
								.then(resolve)
								.catch(reject);
						}, retryConfig.delay);
					} else {
						if (this._errorInterceptor) {
							try {
								this._errorInterceptor(error);
							} catch (interceptorError) {
								return reject(interceptorError);
							}
						}
						reject(error);
					}
				}
			});

			// 上传完成后清除超时定时器（双重保障）
			const originalFinally = task.finally;
			task.finally = function(callback) {
				clearTimeout(timeoutTimer);
				return originalFinally.call(this, callback);
			};
		});
	}

	/**
	 * 下载文件（带重试功能）
	 * @param {String} url 下载URL
	 * @param {Object} options 下载选项
	 * @param {Number} retryCount 当前重试次数
	 * @returns {Promise}
	 */
	download(url, options = {}, retryCount = 0) {
		const {
			filePath,
			header = {},
			timeout = this.config.timeout,
			retry = {},
			cancelToken // 取消令牌
		} = options;

		// 合并重试配置
		const retryConfig = {
			...this.config.retry,
			...retry
		};

		// 验证URL
		if (!url) {
			return Promise.reject(new Error('下载URL不能为空'));
		}

		// 处理URL
		let requestUrl = url;
		if (this.config.baseURL && !url.startsWith('http')) {
			requestUrl = this.config.baseURL + url;
		}

		// 合并请求头
		const requestHeader = {
			...this.config.header,
			...header
		};

		// 构建下载参数
		let downloadOptions = {
			url: requestUrl,
			filePath,
			header: requestHeader,
			timeout
		};

		// 执行请求拦截器
		if (this._requestInterceptor) {
			try {
				const modifiedOptions = this._requestInterceptor(downloadOptions);
				if (modifiedOptions) {
					downloadOptions = modifiedOptions;
				}
			} catch (error) {
				return Promise.reject(error);
			}
		}

		return new Promise((resolve, reject) => {
			// 处理取消请求
			if (cancelToken && this.cancelTokens.has(cancelToken)) {
				this.cancelTokens.set(cancelToken, (reason) => {
					const error = new Error(reason);
					error.code = 'CANCEL';
					reject(error);
				});
			}

			// 超时处理定时器
			const timeoutTimer = setTimeout(() => {
				task.abort();
				const timeoutError = new Error('下载超时');
				timeoutError.code = 'DOWNLOAD_TIMEOUT';

				// 请求完成，移除取消令牌
				if (cancelToken) {
					this.cancelTokens.delete(cancelToken);
				}

				// 检查是否需要重试
				if (retryConfig.count > retryCount &&
					retryConfig.statusCodes.includes(408)) {
					// 延迟重试
					setTimeout(() => {
						this.download(url, options, retryCount + 1)
							.then(resolve)
							.catch(reject);
					}, retryConfig.delay);
				} else {
					if (this._errorInterceptor) {
						try {
							this._errorInterceptor(timeoutError);
						} catch (interceptorError) {
							return reject(interceptorError);
						}
					}
					reject(timeoutError);
				}
			}, timeout);

			const task = uni.downloadFile({
				...downloadOptions,
				success: (response) => {
					// 优先清除超时定时器（关键修复）
					clearTimeout(timeoutTimer);

					// 请求完成，移除取消令牌
					if (cancelToken) {
						this.cancelTokens.delete(cancelToken);
					}

					// 执行响应拦截器
					if (this._responseInterceptor) {
						try {
							const processedResponse = this._responseInterceptor(response);
							resolve(processedResponse);
						} catch (error) {
							// 检查是否需要重试
							if (retryConfig.count > retryCount &&
								retryConfig.statusCodes.includes(response.statusCode)) {
								// 延迟重试
								setTimeout(() => {
									this.download(url, options, retryCount + 1)
										.then(resolve)
										.catch(reject);
								}, retryConfig.delay);
							} else {
								if (this._errorInterceptor) {
									this._errorInterceptor(error);
								}
								reject(error);
							}
						}
					} else {
						resolve(response);
					}
				},
				fail: (error) => {
					// 优先清除超时定时器（关键修复）
					clearTimeout(timeoutTimer);

					// 请求完成，移除取消令牌
					if (cancelToken) {
						this.cancelTokens.delete(cancelToken);
					}

					// 检查是否需要重试（不是取消错误且还有重试次数）
					if (error.code !== 'CANCEL' && retryConfig.count > retryCount) {
						// 延迟重试
						setTimeout(() => {
							this.download(url, options, retryCount + 1)
								.then(resolve)
								.catch(reject);
						}, retryConfig.delay);
					} else {
						if (this._errorInterceptor) {
							try {
								this._errorInterceptor(error);
							} catch (interceptorError) {
								return reject(interceptorError);
							}
						}
						reject(error);
					}
				}
			});

			// 下载完成后清除超时定时器（双重保障）
			const originalFinally = task.finally;
			task.finally = function(callback) {
				clearTimeout(timeoutTimer);
				return originalFinally.call(this, callback);
			};
		});
	}
}

// 创建实例并导出，确保单例
export default new Http();